<?php

namespace App\Services\Product;

use App\Events\DeviceInfoUpdate;
use App\Events\UserCommand;
use App\Exceptions\DeviceException;
use App\Exceptions\UserException;
use App\Facades\ChargeRecordManager;
use App\Facades\UserManager;
use App\Facades\DeviceManager;
use App\Facades\WeChatService;
use App\Jobs\CommandRepeater;
use App\Jobs\SendTemplateMessage;
use App\Models\Device;
use App\Models\DeviceRecord;
use App\Models\UserInfo;
use App\Utils\DeviceServer;
use Cache;
use Carbon\Carbon;
use DB;
use Exception;
use Illuminate\Foundation\Bus\DispatchesJobs;

class DeviceService
{
    use DispatchesJobs;

    /**
     * 绑定
     * @param  string $deviceCode 设备编码
     */
    public function bind($deviceCode, array $bindMessage)
    {
        try{
            DB::transaction(function() use ($deviceCode, $bindMessage) {
                $user = UserManager::getUser();
                $device = DeviceManager::isCreateDeviceRecord($deviceCode);
                UserManager::updateUserInfo($user->id, ['current_device_id' => $device->id]);
                Cache::forget($user->userInfo->open_id);

                if(!empty($template_id = env('BIND_TEMPLATE_ID'))){
                    WeChatService::sendTemplateMessage([
                        'touser' => $user->userInfo->open_id,
                        'template_id' => $template_id,
                        'url' => url('index'),
                        'data' => [
                            'first' => ['value' => $bindMessage['first'], 'color' => '#173177'],
                            'keyword1'  => ['value' => $bindMessage['keyword1'], 'color' => '#173177'],
                            'keyword2'  => ['value' => $bindMessage['keyword2'], 'color' => '#173177'],
                            'remark'    => ['value' => $bindMessage['remark'], 'color' => '#173177']
                        ]
                    ]);
                }
            });
        }catch(Exception $e){
            throw new DeviceException('bind');
        }
    }

    /**
     * 根据设备号解绑设备
     * @param  string $deviceCode 设备编码
     */
    public function unbindByDeviceCode($deviceCode = null)
    {
        try{
            return DB::transaction(function() use ($deviceCode) {
                $userInfo = UserManager::getUser()->userInfo;
                UserManager::updateUserInfo($userInfo->user_id, ['current_device_id' => null]);
                Cache::forget('userInfo'.$userInfo->user_id);
            });
        }catch(Exception $e){
            throw new DeviceException('unbind');
        }
    }

    /**
     * 获取设备状态
     * @return array    设备状态
     */
    public function getState($throwException = true)
    {
        $user = UserManager::getUser();
        $userInfo = $user->userInfo->load(['device' => function($query){
            $query->select('id', 'code', 'recharge_mode');
        }]);
        if(is_null($userInfo->device)){
            throw new DeviceException('noBind');
        }
        $deviceCode = $userInfo->device->code;
        $state = Cache::get($deviceCode.'state');
        if($throwException){
            $this->isOffline($deviceCode);
        }

        if(count($state)){
            return $state;
        }
    }

    /**
     * 发送控制命令
     * @param  string $command 命令
     */
    public function control($command, $num, $deviceCode = null, $orderId = null, $userId = null, $throw = true, $mode = 2)
    {
        // file_put_contents('./aa.txt', 'data');
        if(is_null($deviceCode)){
            if(is_null($userId)){
                $userId = UserManager::getUser()->id;
            }
            $userInfo = Cache::remember('userInfo'.$userId, env('CACHE_USER_INFO_TIME', 1), function() use ($userId) {
                return UserManager::getUserById($userId)->userInfo->load(['device' => function($query){
                    $query->select('id', 'code');
                }]);
            });
            $deviceCode = $userInfo->device->code;
        }

        $state = Cache::get($deviceCode.'state');

        // 判断是否离线   没有离线则执行
        if(!$this->isOffline($deviceCode, $throw)){
            // 没有关机、停机、充值命令     状态不是关机      命令也没有关机 
            if(!in_array($command, ['halt', 'stop_halt', 'recharge']) && $state['decStatus'] == 7 && $command != 'power_on'){
                throw new DeviceException('powerOff');
            }

            // 特殊操作
            if(in_array($command, ['power_on', 'power_off', 'wash', 'wash_cancel'])) {
                $state = Cache::get($deviceCode.'state');
            }
            event(new UserCommand($command, $num, $deviceCode, $orderId, null, $mode));
        }
        //停机和充值的重发队列
        if(in_array($command, [/*'halt', 'stop_halt',*/ 'recharge', 'reduce_flow', 'mode_recharge', 'mode_reduce'])){
            $job = (new CommandRepeater($command, $num, $deviceCode, $orderId, $userId, false, $mode))->delay(20)->onQueue('commandRepeater');
            $this->dispatch($job);
        }
    }

    /**
     * 获取控制指令 byte
     * @param  string  $command   
     * @param  string  $num       
     * @param  string  $deviceCode    
     * @param  integer $orderId 充值记录 id
     * @return              
     */
    public function getCmd($command, $num, $deviceCode, $orderId = 0, $mode = 2)
    {
        $binDeviceCode = Cache::get($deviceCode.'BinDeviceCode');
        switch ($command)
        {
            case 'power_on':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 17, 0x07, 2, 1);
                break;
            case 'power_off':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 17, 0x07, 2, 0);
                break;
            case 'unlock':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 17, 0x07, 4, 1);
                break;
            case 'wash':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 17, 0x07, 1, 1);
                break;
            case 'wash_cancel':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 17, 0x07, 1, 0);
                break;
            case 'reset_filter':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 17, 0x07, 3, $num);
                break;
            case 'halt':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 16, 0x0a, 1);
                DeviceManager::updateDevice($deviceCode, ['status' => Device::STATUS_HALTING], 1);
                break;
            case 'stop_halt':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 16, 0x0a, 0);
                DeviceManager::updateDevice($deviceCode, ['status' => Device::STATUS_HALTING], 0);
                break;
            case 'recharge':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 19, 0x08, $num, 0, $orderId, 0x2b000000);
                break;
            case 'reduce_flow':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 19, 0x08, $num, 0, $orderId, 0x2d000000);
                break;
            case 'mode_recharge':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 25, 0x0d, $num, $mode, $orderId, 0x2b);
                break;
            case 'mode_reduce':
                $cmd = DeviceServer::getCmdByte($binDeviceCode, 25, 0x0d, $num, $mode, $orderId, 0x2d);
                break;
            default:
                throw new DeviceException('command');
                break;
        }
        return $cmd;
    }

    /**
     * 获取设备列表
     * @param   $condition
     * @param   $status
     * @return
     */
    public function findDeviceRecordLlist($condition, $status)
    {
        $resultSet = DeviceManager::findDeviceRecordWithCodeByStatus($status, $condition);
        return $resultSet->orderBy('created_at', 'desc')->paginate(15);
    }

    /**
     * 根据设备码获取设备信息
     * @param   $deviceCode 
     * @return              
     */
    public function findDeviceRecordListByDeviceCode($deviceId)
    {
        $deviceRecords = DeviceManager::getAllDeviceRecordWithCodeByDeviceCode($deviceId)
            ->with(['device' => function($query){
                $query->with(['installInfo' => function($query){
                    $query->select(['device_code', 'customer_name', 'phone', 'installation_address', 'dealer']);
                }])->select(['id', 'code']);
        }])->latest()->paginate(15);

        return $deviceRecords;
    }

    public function getHreatBeatData(){
        return pack("v5C3V2v", 0x00bb, 0x0006, 0x0000, 0x000D, 0x0002, 0x12, 0x00, 0x00, 0X00000000, 0X00000000, 0x4FE5);
    }

    /**
     * 处理设备数据
     * @return  
     */
    public function handle($dataCmd, $fd, $data, $fdInfo)
    {
        $formatData = DeviceServer::dataFormat($dataCmd, $data);

        $device = DeviceManager::isCreateDeviceRecord($formatData['deviceCode']);
        if($dataCmd == 0x0c){
            if($formatData['faultCode'] == 0){
                DeviceManager::updateDeviceFaults($device->id);
            }else{
                DeviceManager::addDeviceFaultRecord([
                    'device_id' => $device->id,
                    'fault_code' => $formatData['faultCode']]);
            }
        }
        //缓存设备数据
        $formatData = $this->cacheDeviceData($formatData, $fd, $data, $dataCmd, $device->recharge_mode);

        if($formatData['decStatus'] == DeviceRecord::HALT){
            if($device->status != Device::STATUS_HALT){
                $device->update(['status' => Device::STATUS_HALT]);
            }
        }else{
            if($device->status == Device::STATUS_HALT){
                $device->update(['status' => Device::STATUS_WORK]);
            }
        }
        event(new DeviceInfoUpdate($formatData));
        
        if(in_array(4, $formatData['cmd']) && $formatData['residualFlow']<=45 && !empty(env('REMIND_TEMPLATE_ID'))){
            $this->dispatch(new SendTemplateMessage($formatData));
        }

        $this->isSaveDeviceData($formatData, $fdInfo);
    }

    /**
     * 缓存设备相关信息
     * @param   $formatData 
     * @param   $fd         
     * @param   $data       
     * @return              
     */
    public function cacheDeviceData($formatData, $fd, $data, $dataCmd, $rechargeMode)
    {
        $expiresAt = Carbon::now()->addMinutes(env('CACHE_DEVICE_DATA'));
        // dd($expiresAt);
        $formatDataCache = Cache::remember($formatData['deviceCode'].'state', $expiresAt, function() use ($formatData) {
            return $formatData = [
                'deviceCode' => $formatData['deviceCode'],
                'messageNumber' => 0,
                'decStatus' => 0,
                'decStatusDescription' => '离线',
                'TDS1' => '000',
                'TDS2' => '000',
                'filterCnt1' => 0,
                'filterCnt2' => 0,
                'filterCnt3' => 0,
                'filterCnt4' => 0,
                'filterCnt5' => 0,
                'filterSet1' => 1,
                'filterSet2' => 1,
                'filterSet3' => 1,
                'filterSet4' => 1,
                'filterSet5' => 1,
                'filter1' => 0,
                'filter2' => 0,
                'filter3' => 0,
                'filter4' => 0,
                'filter5' => 0,
                'totalFlow' => 0,
                'residualFlow' => 0,
                'timeLimit' => 0,
                'amountWater' => 0,
                'cmd' => [],
            ];
        });
        $keys = [
            'messageNumber',
            'decStatus',
            'decStatusDescription',
            'TDS1',
            'TDS2',
            'filterCnt1',
            'filterCnt2',
            'filterCnt3',
            'filterCnt4',
            'filterCnt5',
            'filterSet1',
            'filterSet2',
            'filterSet3',
            'filterSet4',
            'filterSet5',
            'filter1',
            'filter2',
            'filter3',
            'filter4',
            'filter5',
            'totalFlow',
            'residualFlow',
            'timeLimit',
            'amountWater',
        ];
        foreach($keys as $key){
            if(array_key_exists($key, $formatData)){
                $formatDataCache[$key] = $formatData[$key];
            }
        }
        $formatDataCache['rechargeMode'] = $rechargeMode;
        //缓存设备连接 fd
        Cache::put($formatData['deviceCode'].'fd', $fd, $expiresAt);
        
        if(!in_array($dataCmd, $formatDataCache['cmd'])){
            $formatDataCache['cmd'][] = $dataCmd;
        }
        //缓存设备数据
        Cache::put($formatData['deviceCode'].'state', $formatDataCache, $expiresAt);
        
        //缓存设备码二进制数据
        Cache::put($formatData['deviceCode'].'BinDeviceCode', substr($data, 9, 8), $expiresAt);
        return $formatDataCache;
    }

    /**
     * 发送模板消息
     * @param  UserInfo  $userInfo
     * @param  array     $data 
     * @return              
     */
    public function sendTemplateMessage($userInfo, array $data)
    {
        if($data['residualFlow'] > 20){
            $remind = '不足45L';
        }else if($data['residualFlow'] > 0){
            $remind = '不足20L';
        }else{
            $remind = '用完，即将停机';
        }
        
        WeChatService::sendTemplateMessage([
            'touser' => $userInfo->open_id,
            'template_id' => env('REMIND_TEMPLATE_ID'),
            'url' => url('/user/payFlux'),
            'data' => [
                'first' => ['value' => '尊敬的用户：您使用的鹤庭净水设备当前流量已'.$remind.'为不影响您的使用，请尽快充值！', 'color' => '#173177'],
                'keyword1'  => ['value' => $data['deviceCode'], 'color' => '#173177'],
                'keyword2'  => ['value' => '400-800-5063', 'color' => '#173177'],
                'remark'    => ['value' => '您可以使用鹤庭净水微信公众号客户端充值或点击“快速充值”', 'color' => '#173177']
            ]
        ]);
    }

    /**
     * 存储记录
     * @param   $formatData 
     * @return              
     */
    public function isSaveDeviceData($formatData, $fdInfo)
    {
        if((substr($formatData['deviceCode'], 0, 2) == '20' && count(array_diff([1, 2, 3, 4], $formatData['cmd'])) == 0) || 
            (substr($formatData['deviceCode'], 0, 2) == '21' && count(array_diff([1, 2, 3, 4, 15, 16], $formatData['cmd'])) == 0)){
            $marks = [
                'recordHydropenia' => DeviceRecord::HYDROPENIA,
                'recordOverhaul' => DeviceRecord::OVERHAUL,
                'recordHalt' => DeviceRecord::HALT,
                'recordLeakage' => DeviceRecord::LEAKAGE,
            ];
            foreach($marks as $key => $value){
                if($formatData['decStatus'] == $value && !Cache::has($formatData['deviceCode'].$key)){
                    $this->saveDeviceData($formatData);
                    Cache::put($formatData['deviceCode'].$key, 1, Carbon::now()->addMinutes(60*24));
                    Cache::put($formatData['deviceCode'].'electrify', 1, Carbon::now()->addMinutes(60));
                    Cache::forget($formatData['deviceCode'].'record');
                }
            }
            if(($fdInfo['last_time'] - $fdInfo['connect_time'] > 10) && $formatData['messageNumber'] < 18 && !Cache::has($formatData['deviceCode'].'electrify')){
                $this->saveDeviceData($formatData);
                Cache::put($formatData['deviceCode'].'electrify', 1, Carbon::now()->addMinutes(60));
            }else if(in_array($formatData['decStatus'], [1, 3, 5, 6, 7]) && !Cache::has($formatData['deviceCode'].'record')){
                $this->saveDeviceData($formatData);
                Cache::put($formatData['deviceCode'].'record', 1, Carbon::now()->addMinutes(60*24));
                Cache::put($formatData['deviceCode'].'electrify', 1, Carbon::now()->addMinutes(60));
                Cache::forget($formatData['deviceCode'].'recordHydropenia');
                Cache::forget($formatData['deviceCode'].'recordOverhaul');
                Cache::forget($formatData['deviceCode'].'recordHalt');
                Cache::forget($formatData['deviceCode'].'recordLeakage');
            }else{
                if(Cache::has($formatData['deviceCode'].'recharge')){
                    Cache::forget($formatData['deviceCode'].'recharge');
                    $this->saveDeviceData($formatData);
                }
            }   
        }
    }

    /**
     * 保存设备记录数据
     * @param  [type] $formatData 
     * @return [type]             
     */
    public function saveDeviceData($formatData)
    {
        $createData = [
            'device_code' => $formatData['deviceCode'],
            'TDS1' => $formatData['TDS1'],
            'TDS2' => $formatData['TDS2'],
            'message_number' => $formatData['messageNumber'],
            'dec_status' => $formatData['decStatus'],
            'filter_cnt1' => $formatData['filterCnt1'],
            'filter_cnt2' => $formatData['filterCnt2'],
            'filter_cnt3' => $formatData['filterCnt3'],
            'filter_cnt4' => $formatData['filterCnt4'],
            'filter_cnt5' => $formatData['filterCnt5'],
            'filter_set1' => $formatData['filterSet1'],
            'filter_set2' => $formatData['filterSet2'],
            'filter_set3' => $formatData['filterSet3'],
            'filter_set4' => $formatData['filterSet4'],
            'filter_set5' => $formatData['filterSet5'],
            'filter1' => $formatData['filter1'],
            'filter2' => $formatData['filter2'],
            'filter3' => $formatData['filter3'],
            'filter4' => $formatData['filter4'],
            'filter5' => $formatData['filter5'],
            'total_flow' => $formatData['totalFlow'],
            'residual_flow' => $formatData['residualFlow'],
            'time_limit' => $formatData['timeLimit'],
            'amount_water' => $formatData['amountWater'],
            'recharge_mode' => $formatData['rechargeMode'],
        ];
        DeviceManager::save($createData);
    }

    public function sendHeartBeatData($fd)
    {
        event(new UserCommand('heart_beat_data', null, $fd));
    }

    /**
     * 根据用户获取设备码
     * @return [type] 
     */
    public function getDeviceCodeByUser()
    {
        $userInfo = UserManager::getUser()->userInfo;
        if(is_null($userInfo->device)){
            throw new DeviceException('noBind');
        }
        $userInfo->load(['device' => function($query){
            $query->select('id', 'code', 'recharge_mode');
        }]);
        return $userInfo->device;
    }

    /**
     * 设备是否离线
     * @param  string  $deviceCode 
     * @param  boolean $throw      
     * @return boolean             
     */
    public function isOffline($deviceCode, $throw = true)
    {
        $fd = Cache::get($deviceCode.'fd');
        $fds = Cache::get('fds');
        if($throw){
            if(is_null($fd) || is_null($fds) || !in_array($fd, $fds)){
                Cache::forget($deviceCode.'state');
                throw new DeviceException('notConnect');
            }
        }else{
            $result = (is_null($fd) || is_null($fds) || !in_array($fd, $fds));
            if($result){
                Cache::forget($deviceCode.'state');
            }
            return $result;
        }
    }

    /**
     * 更新设备记录数据
     * @param  integer $id   
     * @param  array $data 
     * @return        
     */
    public function update($id, $data)
    {
        $deviceRecord = DeviceManager::getDeviceRecordById($id);
        $deviceRecord->update($data);
        return $deviceRecord;
    }

    /**
     * 获取设备提醒列表
     * @param  string  $condition 
     * @return              
     */
    public function findFlowRemindList($condition)
    {
        $listBuilder = DeviceManager::getDeviceRemindList($condition);
        $listBuilder->where(function($query){
            $query->where('residual_flow', '<=', 100)
                ->whereExists(function($query){
                    $query->select('recharge_mode')
                        ->from('devices')
                        ->whereRaw('devices.id = device_records.device_id')
                        ->where('recharge_mode', '=', 2);
                })->orWhere(function($query){
                $query->where('time_limit', '<=', 20)
                    ->whereExists(function($query){
                        $query->select('recharge_mode')
                            ->from('devices')
                            ->whereRaw('devices.id = device_records.device_id')
                            ->where('recharge_mode', '=', 1);
                    });
                });
        });
        return $listBuilder->orderBy('flow_status')->orderBy('residual_flow')->orderBy('time_limit')->latest()->select([
                                                                                    'id',
                                                                                    'device_id',
                                                                                    'residual_flow',
                                                                                    'created_at',
                                                                                    'flow_status',
                                                                                    'time_limit',
                                                                                    'recharge_mode',
                                                                                    ])->paginate(15);
    }

    /**
     * 获取设备提醒列表
     * @param  string  $condition 
     * @return              
     */
    public function findFliterRemindList($condition)
    {
        $listBuilder = DeviceManager::getDeviceRemindList($condition);
        $listBuilder->where(function($query){
            for($i=1; $i<=4; $i++){
                $query->orWhere('filter'.$i, '<=', 15);
            }
        });
        return $listBuilder->orderBy('filter_status')
                           ->orderBy('filter1')
                           ->orderBy('filter2')
                           ->orderBy('filter3')
                           ->orderBy('filter4')
                           ->orderBy('filter5')
                           ->latest()
                           ->select([
                                    'id',
                                    'device_id',
                                    'filter1',
                                    'filter2',
                                    'filter3',
                                    'filter4',
                                    'filter5',
                                    'created_at',
                                    'filter_status',
                                        ])
                            ->paginate(15);
        
    }

    /**
     * 根据状态对设备提醒记录计数
     * @param integer  $status 
     * @return          
     */
    public function countFlowRemindListByStatus($status)
    {
        return DeviceManager::countFlowRemindListByStatus($status);
    }

    /**
     * 根据状态对设备提醒记录计数
     * @param integer  $status 
     * @return          
     */
    public function countFilterRemindListByStatus($status)
    {
        return DeviceManager::countFilterRemindListByStatus($status);
    }

    /**
     * 根据状态对维护信息记录计数
     * @param integer  $status 
     * @return          
     */
    public function countmaintainInfoListByStatus($status)
    {
        return DeviceManager::getMaintainInfoListBuilderOrderBy('status')->where('status', $status)->count();
    }

    public function getInstallAddressByDeviceCode($deviceCode)
    {
        return DeviceManager::getInstallInfoByQueryColumn('device_code', $deviceCode)->installation_address;
    }

    public function getInstallerByQueryColumn($condition)
    {
        return DeviceManager::getInstallerByQuery($condition);
    }

    public function getDealerByQueryColumn($condition)
    {
        return DeviceManager::getDealerByQuery($condition);
    }

    public function getDeviceCodeByid($deviceId)
    {
        $device = DeviceManager::getDeviceByQuery('id', $deviceId);
        if(is_null($device)){
            throw new DeviceException('notFound');
        }
        return $device->code;
    }

    public function getDeviceFaults($condition)
    {
        $builder = DeviceManager::getDeviceFaultLatestBuilder()->with(['device' => function($query){
            $query->with(['installInfo' => function($query){
                $query->select(['device_code', 'customer_name', 'phone', 'dealer']);
            }]) ->select(['id', 'code']);
        }]);
        // if(!empty($condition)){
        //  $builder->where();
        // }
        return $builder->paginate(15, [
            'device_faults.device_id',
            'device_faults.fault_code',
            'device_faults.created_at',
            ]);
    }

    /**
     * 获取设备 tds 提醒列表
     * @param  string  $condition 
     * @return              
     */
    public function findTdsRemindList($condition)
    {
        $listBuilder = DeviceManager::getDeviceRemindList($condition);
        $listBuilder->where('TDS2', '>=', 45);
        return $listBuilder->orderBy('TDS2', 'desc')->latest()->select([
                                                                        'id',
                                                                        'device_id',
                                                                        'TDS2',
                                                                        'created_at',
                                                                        ])->paginate(15);
    }

    /**
     * 获取设备非正常工作状态提醒列表
     * @param  string  $condition 
     * @return              
     */
    public function findStatusRemindList($condition)
    {
        $listBuilder = DeviceManager::getDeviceRemindList($condition);
        $listBuilder->whereIn('dec_status', [2, 4, 6, 8, 9]);
        return $listBuilder->orderBy('TDS2', 'desc')->latest()->select([
                                                                        'id',
                                                                        'device_id',
                                                                        'dec_status',
                                                                        'created_at',
                                                                        ])->paginate(15);
    }

    public function countTdsRemindList()
    {
        return DeviceManager::countTdsRemindList();
    }

    public function countStatusRemindList()
    {
        return DeviceManager::countStatusRemindList();
    }

    public function getStateByDeviceCode($deviceCode)
    {
        return Cache::get($deviceCode.'state');
    }

    public function isExceedMaxRechargeAmount($deviceCode, $rechargeAmount, $rechargeMode = 2)
    {
        //查询设备上的状态
        $state = $this->getStateByDeviceCode($deviceCode);
        
        if(!count($state)){
            $device = DeviceManager::getDeviceByQuery('code', $deviceCode);
            $state = DeviceManager::getDeviceRecordBuilderByQuery('device_id', $device->id)->latest()->first(['device_id', 'time_limit', 'residual_flow']);
        }
        switch($rechargeMode)
        {
            case 1:
                if((is_array($state) && $state['timeLimit']+ $rechargeAmount > 10000) || (is_object($state) && $state->time_limit+ $rechargeAmount > 10000)){
                    throw new DeviceException('rechargeAmountTooLarge');
                }
                break;
            case 2:
                if((is_array($state) && $state['residualFlow']+ $rechargeAmount > 65000) || (is_object($state) && $state->residual_flow+ $rechargeAmount > 65000)){
                    throw new DeviceException('rechargeAmountTooLarge');
                }
                break;
            default:
                break;
        }
        return $state;
    }

    public function canRecharge($deviceCode, $rechargeMode)
    {
        $device = DeviceManager::getDeviceByQuery('code', $deviceCode);
        if(is_null($device)){
            throw new DeviceException('notFound');
        }
        if($device->recharge_mode != $rechargeMode){
            throw new DeviceException('rechargeMode');
        }
    }

}